home *** CD-ROM | disk | FTP | other *** search
- ; MyMouse
- ; Bit to handle screen-activewindow associative table
- ; Andrew Forrest
- ;****************************************************************************
- ; The program manages the table as a linked list of blocks. Each block
- ; contains up to a maximum number of (screen, activewindow) pairs. The head
- ; of the list is the most recently-accessed pair.
- ; All these routines should be called with Intuitionbase locked.
- ; No arbitration is done for access to screen table, so only one task at a
- ; time please.
- ;***************************************************************************
- ; USES:
- ; Globals.ScreenTable (the abstract object itself)
- ; EXPORTS:
- ; InitialiseScreenTable() ; Call this first
- ; ShutDownScreenTable() ; Call this last
- ; AssociateWindow(Screen, Window) ; Insert a tuple in the table
- ; IndexScreenTable(Screen) : Window ; Look up a tuple
- ; PruneScreenTable() ; Remove redundant entries
- ;
- ;***************************************************************************
- ; Table is represented as a linked list of blocks, each with up to
- ; TuplesPerChunk tuples. (Each chunk in the table is an Exec minnode.)
-
- ; The last chunk may be partially-empty, in which case the remaining spaces
- ; are filled with NULL screen pointers. It is vitally important (to
- ; PruneScreenTable()) that _only_ the last node is padded with NULLs.
- ; ScreenTable.LastTupleOffset is the offset (from its chunk) of the last
- ; non-NULL tuple in the table. This can be 0 is last node is empty (entirely
- ; NULL) or undefined if there are no chunks. FirstTupleOffset is unused.
-
- TuplesPerChunk equ 7 ; Ideally a power of 2 minus 1
-
- STRUCTURE ScreenWindowTuple,0
- APTR Tuple_Screen
- APTR Tuple_Window
- LABEL Tuple_SIZEOF
-
- STRUCTURE ScreenTableChunk,MLN_SIZE
- STRUCT Chunk_Data,Tuple_SIZEOF*TuplesPerChunk
- LABEL Chunk_SIZEOF
-
- STRUCTURE ScreenTableType,MLH_SIZE
- WORD ST_FirstTupleOffset ; \ Byte offset from chunk to
- WORD ST_LastTupleOffset ; / start of first/last tuple
- LABEL ST_SIZEOF
-
- ; PRIVATE routine to find the tuple associated with a particular screen if it
- ; can be found. Takes a0=^screen; Uses a5=^globals (for ScreenTable)
- ; Returns (d0=^chunk; d1=tup offset | d0=NULL; d1=?); Trashes nil.
- FindScreenTuple:
- pushm.l a1/d2
- move.l a0,d0 ;\ Return a NULL if
- beq.s .null ;/ ^screen is NULL
- move.l ScreenTable+MLH_HEAD(a5),a1
- .loop move.l MLN_SUCC(a1),d0 ; d0 <- node after this one
- beq.s .null ; fail if this is not really a node (the `next node' of the list header TAILPRED is NULL)
- moveq #Chunk_Data,d1 ; d1 <- offset of first tuple
- moveq #TuplesPerChunk-1,d2
- .dataloop cmp.l Tuple_Screen(a1,d1),a0
- beq.s .succeed ; Exit early if we _do_ find the screen
- addq.l #Tuple_SIZEOF,d1 ; Get to next bit of data
- dbra d2,.dataloop
- move.l d0,a1 ; Get the next node
- bra.s .loop
- .succeed move.l a1,d0 ; d0 <- ^this chunk
- .null popm.l a1/d2 ; If we jump to here, d0 will equal NULL
- rts
-
- ; Routine to make screen table ready for use. Allocates all the necessary
- ; resources. Structure must initially be zeroed.
- ; Uses a5=^Globals (for ScreenTable); Trashes & Returns nil;
- InitialiseScreenTable:
- ; << Shares code with ShutDownScreenTable >>
-
- ; Routine to deallocate all of the screen table's resources and generally
- ; shut up shop. May be called even if structure is uninitialised (zeroed).
- ; Leaves screen table in an initialised state. (Deallocation is done
- ; without keeping the list consistant betweentimes.)
- ; Uses a5=^Globals (for ScreenTable)
- ShutDownScreenTable:
- pushm.l a0-a2/d0-d2/a6
- move.l Execbase,a6
- lea ScreenTable+MLH_HEAD(a5),a2
- move.l (a2),d2
- beq.s .end ; Quit early if not initialised
- .loop move.l d2,a1 ; thisnode <- nextnode
- move.l MLN_SUCC(a1),d2 ; nextnode <- thisnode.NEXT
- beq.s .end ; Exit if no next node (in list header)
- move.l #Chunk_SIZEOF,d0
- just FreeMem ; Free the memory of this node
- bra.s .loop ; Keep looping 'til end of list
- .end NEWLIST a2 ; Make listheader self-consistant again
- clr.l ScreenTable+ST_FirstTupleOffset(a5) ; Clears TWO words
- popm.l a0-a2/d0-d2/a6
- rts
-
- ; Routine to associate a particular window with a particular screen.
- ; Takes a0=^screen; a1=^window; Returns nil; Trashes nil.
- ; Uses a5=^globals (for ScreenTable and (locked) Intbase)
- ; Uses a2=^tuple; d1=last tuple offset; also a2,a3 = pointers to chunks
- AssociateWindow:
- cmp.w #0,a0 ; \ First check that we have not been
- beq.s .return ; / passed a NULL screen pointer
- pushm.l a2-a3/d0-d1
- bsr FindScreenTuple
- move.l d0,a2 ; a2 <- pointer to chunk
- tst.l d0
- bne.s .found ; If FindScreenTuple(..) == NULL
- move.l ScreenTable+MLH_TAILPRED(a5),a2 ; Get last chunk
- tst.l MLN_PRED(a2) ; Does it have a predecessor?
- beq.s .new_chunk ; (If not, it isn't a proper node)
- move.w ScreenTable+ST_LastTupleOffset(a5),d1
- addq.w #Tuple_SIZEOF,d1 ; Compute new LastTuple offset
- cmp.w #Chunk_SIZEOF,d1
- blo.s .enoughroom ; If last chunk is full up...
- .new_chunk pushm.l a0-a1/a6
- move.l Execbase,a6
- move.l #Chunk_SIZEOF,d0
- move.l #MEMF_CLEAR,d1
- just AllocMem ; ...allocate a new one
- popm.l a0-a1/a6
- tst.l d0
- beq.s .end ; (Can't allocate memory, so give up)
- move.l d0,MLN_SUCC(a2)
- exg d0,a2 ; d0 <- ^prev chunk; a2 <- ^new chunk
- move.l d0,MLN_PRED(a2)
- lea ScreenTable+MLH_TAIL(a5),a3 ; a3 <- ^next chnk
- move.l a2,MLN_PRED(a3)
- move.l a3,MLN_SUCC(a2)
- moveq #Chunk_Data,d1
- .enoughroom move.w d1,ScreenTable+ST_LastTupleOffset(a5)
- move.l a0,Tuple_Screen(a2,d1.w)
- .found move.l a1,Tuple_Window(a2,d1.w)
- .end popm.l a2-a3/d0-d1
- .return rts
-
-
- ; Routine to look up a screen in the table and return its associated window.
- ; Checks for existance of window. If window not in screen, returns frontmost
- ; window. WARNING: does not check for the existance of the screen (but does
- ; accept a NULL screen pointer, to which it returns NULL).
- ; Takes a0=^screen. Uses a5=^globals (uses ScreenTable and (locked) Intbase)
- ; Returns d0=^window. Trashes nil.
- IndexScreenTable:
- pushm.l a0-a1/d1
- bsr FindScreenTuple
- tst.l d0
- beq.s .end ; Exit with d0=null if can't find screen
- move.l d0,a1
- move.l Tuple_Window(a1,d1.w),d0
- move.l sc_FirstWindow(a0),d1 ; Get first window in screen
- .windloop beq.s .closed ; Return front window if no more windows
- cmp.l d1,d0 ; Is this the window we seek?
- beq.s .end ; Found window in screen: success
- move.l d1,a1
- move.l wd_NextWindow(a1),d1 ; Else look at _next_ window
- bra.s .windloop ; Keep looping 'til no more windows
- .end popm.l a0-a1/d1
- rts
- .closed move.l sc_FirstWindow(a0),d0 ; Return the frontmost window
- bra.s .end ; ...and exit
-
- ; This routine garbage-collects non-existant (closed) screens from the table.
- ; Takes nil; Uses a5=^globals (for ScreenTable and (locked) Intbase)
- ; Returns nil; Trashes nil.
- ; Uses a0=^this chunk; d0=tuple offset; a1=^last chunk; d1=last tuple offset
- ; a2=^first screen; d2=^search screen; a3=^this screen; d3=tuple count
- ; a6=^execbase
- PruneScreenTable:
- pushm.l a0-a3/a6/d0-d3
- move.w ScreenTable+ST_LastTupleOffset(a5),d1
- move.l Execbase,a6
- move.l IntBase(a5),a2
- move.l ib_FirstScreen(a2),a2
- lea ScreenTable+MLH_HEAD(a5),a0
- move.l ScreenTable+MLH_TAILPRED(a5),a1 ; (It's okay: we check to see if the first node exists, and if _it_ exists, there must be a last node too.)
- .nextchunk move.l MLN_SUCC(a0),a0 ; Get next chunk after this
- tst.l MLN_SUCC(a0) ; (Do it this way in case the successor node changes (is removed) while we have a cached next-node pointer, for example.)
- beq.s .endchunks ; Exit if we are back to list header
- moveq #Chunk_Data,d0 ; Offset of actual data
- moveq #TuplesPerChunk-1,d3 ; Repeat TuplesPerChunk times
- .tupleloop move.l Tuple_Screen(a0,d0.w),d2 ; Get next tuple in chunk
- beq.s .endchunks ; NULL screen occurs only at end of list
- lea (a2),a3 ; Get the first screen on the system list
- .screenloop cmp.l a3,d2 ; Is this the screen we are looking for?
- beq.s .nexttuple ; If found, on to next tuple
- cmp.w #0,a3 ; End of screen list?
- movea.l sc_NextScreen(a3),a3 ; (CCR unaffected)
- bne.s .screenloop ; Stop looping at list end
- bsr.s .removescrn
- .nexttuple addq.w #Tuple_SIZEOF,d0 ; Offset of next datum
- dbra d3,.tupleloop ; Loop on TuplesPerChunk
- bra.s .nextchunk ; Loop on chunks
- .endchunks move.w d1,ScreenTable+ST_LastTupleOffset(a5)
- popm.l a0-a3/a6/d0-d3
- rts
-
- ; Assume this bit is called only when:
- ; a Tuple is to be removed; there are chunks in the list;
- ; list is consistant and correct (very important);
- ; a1=^last chunk; d1=LastTupOffset;
- ; a0=^chunk; d0=offset (from a0) of any non-NULL tuple in list
- ; If these rules are obeyed, we won't deallocate current node.
- .removescrn tst.w d1
- bne.s .dataleft ; \ If LastTupleOffset==NULL, deallocate
- pushm.l a0/d0 ; / the last chunk
- move.l LN_SUCC(a1),a0 ; a0 <- tail of list
- move.l LN_PRED(a1),a3 ; a3 <- last chunk but one
- move.l a0,LN_SUCC(a3)
- move.l a3,LN_PRED(a0)
- move.l #Chunk_SIZEOF,d0
- just FreeMem
- lea (a3),a1 ; Now get the _new_ last chunk
- move.l #Chunk_SIZEOF-Tuple_SIZEOF,d1
- popm.l a0/d0
- .dataleft move.l Tuple_Screen(a1,d1.w),Tuple_Screen(a0,d0.w)
- move.l Tuple_Window(a1,d1.w),Tuple_Window(a0,d0.w)
- clr.l Tuple_Screen(a1,d1.w) ; | Replace this tuple with
- clr.l Tuple_Window(a1,d1.w) ; / the last one in the table
- subq.w #Tuple_SIZEOF,d1
- rts
-
-